﻿<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Cesium VolumeRendering</title>
    <meta charset="utf-8" />
    <link href="../../../ThirdParty/Cesium/Widgets/widgets.css" rel="stylesheet" />
    <style>
        html, body, #cesiumContainer {
            width: calc(100%);
            height: calc(100%);
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>

    <div id="cesiumContainer">
    </div>
    <div id="creditContainer" style="display: none;">
    </div>

    <script id="fragmentShaderFirstPass" type="x-shader/x-fragment">
        varying vec3 worldSpaceCoords;

        void main()
        {
        //The fragment's world space coordinates as fragment output.
        gl_FragColor = vec4( worldSpaceCoords.x , worldSpaceCoords.y, worldSpaceCoords.z, 1 );
        }
    </script>
    <script id="vertexShaderFirstPass" type="x-shader/x-vertex">
        attribute vec3 position;
        varying vec3 worldSpaceCoords;
        uniform mat4 projectionMatrix;
        uniform mat4 modelViewMatrix;
        uniform vec3 dimensions;

        void main()
        {
        //Set the world space coordinates of the back faces vertices as output.
        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        worldSpaceCoords=(position+dimensions/2.0)/dimensions;
        }
    </script>
    <script id="fragmentShaderSecondPass" type="x-shader/x-fragment">
        varying vec3 worldSpaceCoords;
        varying vec4 projectedCoords;
        uniform sampler2D tex, cubeTex, transferTex;
        uniform float steps;
        uniform float alphaCorrection;
        uniform vec3 dimensions;
        uniform float alpha;

        // The maximum distance through our rendering volume is sqrt(3).
        // The maximum number of steps we take to travel a distance of 1 is 512.
        // ceil( sqrt(3) * 512 ) = 887
        // This prevents the back of the image from getting cut off when steps=512 & viewing diagonally.
        const int MAX_STEPS = 887;

        //Acts like a texture3D using Z slices and trilinear filtering.
        vec4 sampleAs3DTexture( vec3 texCoord )
        {
        vec4 colorSlice1, colorSlice2;
        vec2 texCoordSlice1, texCoordSlice2;

        //The z coordinate determines which Z slice we have to look for.
        //Z slice number goes from 0 to 255.
        float zSliceNumber1 = floor(texCoord.z  * 255.0);

        //As we use trilinear we go the next Z slice.
        float zSliceNumber2 = min( zSliceNumber1 + 1.0, 255.0); //Clamp to 255

        //The Z slices are stored in a matrix of 16x16 of Z slices.
        //The original UV coordinates have to be rescaled by the tile numbers in each row and column.
        texCoord.xy /= 16.0;

        texCoordSlice1 = texCoordSlice2 = texCoord.xy;

        //Add an offset to the original UV coordinates depending on the row and column number.
        texCoordSlice1.x += (mod(zSliceNumber1, 16.0 ) / 16.0);
        texCoordSlice1.y += floor((255.0 - zSliceNumber1) / 16.0) / 16.0;

        texCoordSlice2.x += (mod(zSliceNumber2, 16.0 ) / 16.0);
        texCoordSlice2.y += floor((255.0 - zSliceNumber2) / 16.0) / 16.0;

        //Get the opacity value from the 2D texture.
        //Bilinear filtering is done at each texture2D by default.
        colorSlice1 = texture2D( cubeTex, texCoordSlice1 );
        colorSlice2 = texture2D( cubeTex, texCoordSlice2 );

        //Based on the opacity obtained earlier, get the RGB color in the transfer function texture.
        colorSlice1.rgb = texture2D( transferTex, vec2( colorSlice1.a, 1.0) ).rgb;
        colorSlice2.rgb = texture2D( transferTex, vec2( colorSlice2.a, 1.0) ).rgb;

        //How distant is zSlice1 to ZSlice2. Used to interpolate between one Z slice and the other.
        float zDifference = mod(texCoord.z * 255.0, 1.0);

        //Finally interpolate between the two intermediate colors of each Z slice.
        return mix(colorSlice1, colorSlice2, zDifference) ;
        }


        void main( void ) {

        //Transform the coordinates it from [-1;1] to [0;1]
        vec2 texc = vec2(((projectedCoords.x / projectedCoords.w) + 1.0 ) / 2.0,
        ((projectedCoords.y / projectedCoords.w) + 1.0 ) / 2.0 );

        //The back position is the world space position stored in the texture.
        vec3 backPos = texture2D(tex, texc).xyz;

        //The front position is the world space position of the second render pass.
        vec3 frontPos =  worldSpaceCoords;//texture2D(frontPosTex, texc).xyz; //

        //The direction from the front position to back position.
        vec3 dir = backPos - frontPos;

        float rayLength = length(dir);

        //Calculate how long to increment in each step.
        float delta = 1.0 / steps;

        //The increment in each direction for each step.
        vec3 deltaDirection = normalize(dir) * delta;
        float deltaDirectionLength = length(deltaDirection);

        //Start the ray casting from the front position.
        vec3 currentPosition = frontPos;

        //The color accumulator.
        vec4 accumulatedColor = vec4(0.0);

        //The alpha value accumulated so far.
        float accumulatedAlpha = 0.0;

        //How long has the ray travelled so far.
        float accumulatedLength = 0.0;

        //If we have twice as many samples, we only need ~1/2 the alpha per sample.
        //Scaling by 256/10 just happens to give a good value for the alphaCorrection slider.
        float alphaScaleFactor = 25.6 * delta;

        vec4 colorSample;
        float alphaSample;

        //Perform the ray marching iterations
        for(int i = 0; i < MAX_STEPS; i++)
        {
        //Get the voxel intensity value from the 3D texture.
        colorSample = sampleAs3DTexture( currentPosition );

        //Allow the alpha correction customization.
        alphaSample = colorSample.a * alphaCorrection;

        //Applying this effect to both the color and alpha accumulation results in more realistic transparency.
        alphaSample *= (1.0 - accumulatedAlpha);

        //Scaling alpha by the number of steps makes the final color invariant to the step size.
        alphaSample *= alphaScaleFactor;

        //Perform the composition.
        accumulatedColor += colorSample * alphaSample;

        //Store the alpha accumulated so far.
        accumulatedAlpha += alphaSample;

        //Advance the ray.
        currentPosition += deltaDirection;
        accumulatedLength += deltaDirectionLength;

        //If the length traversed is more than the ray length, or if the alpha accumulated reaches 1.0 then exit.
        if(accumulatedLength >= rayLength || accumulatedAlpha >= 1.0 )
        break;
        }
        if(alpha >=0.0 && alpha <= 1.0){
        gl_FragColor  = vec4(accumulatedColor.rgb,alpha);
        }else{
        gl_FragColor  =    accumulatedColor  ;
        }
        //gl_FragColor  =    accumulatedColor  ;//vec4(backPos,1.0); //vec4(accumulatedColor.rgb,1);//

        }
    </script>

    <script id="vertexShaderSecondPass" type="x-shader/x-vertex">
        attribute vec3 position;
        varying vec3 worldSpaceCoords;
        varying vec4 projectedCoords;
        uniform mat4 projectionMatrix;
        uniform mat4 modelViewMatrix;
        uniform vec3 dimensions;

        void main()
        {
        gl_Position = projectionMatrix *  modelViewMatrix * vec4( position, 1.0 );
        projectedCoords =  projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        worldSpaceCoords=(position+dimensions/2.0)/dimensions;

        }
    </script>

    <script src="../../../ThirdParty/Cesium/Cesium.js" type="text/javascript"></script>
    <script src="../../../appconfig.js"></script>
    <script src="../../../dist/CesiumMeshVisualizer.min.js"></script>
    <script src="../common.js"></script>
    <script src="index.js"></script>
    <!--使用requirejs模块管理库进行加载-->
    <!--<script src="../../../ThirdParty/require.js" type="text/javascript" data-main="./index"></script>-->

</body>
</html>
